import os
import sys
import urllib.request
import threading
import pandas as pd
import io
import time
import zmq

class TickThread(threading.Thread):
    baseUrl = "http://hq.sinajs.cn/list="

    def insertEmptyRecord(self,code):
        self.frameData["code"].append(code)
        self.frameData["name"].append("")
        self.frameData["open"].append(0.)
        self.frameData["last_close"].append(0.)
        self.frameData["current"].append(0.)
        self.frameData["highest"].append(0.)
        self.frameData["lowest"].append(0.)
        self.frameData["total_volume"].append(0)
        self.frameData["total_value"].append(0.)
        self.frameData["bid_1_price"].append(0.)
        self.frameData["bid_1_volume"].append(0)
        self.frameData["bid_2_price"].append(0.)
        self.frameData["bid_2_volume"].append(0)
        self.frameData["bid_3_price"].append(0.)
        self.frameData["bid_3_volume"].append(0)
        self.frameData["bid_4_price"].append(0.)
        self.frameData["bid_4_volume"].append(0)
        self.frameData["bid_5_price"].append(0.)
        self.frameData["bid_5_volume"].append(0)
        self.frameData["ask_1_price"].append(0.)
        self.frameData["ask_1_volume"].append(0)
        self.frameData["ask_2_price"].append(0.)
        self.frameData["ask_2_volume"].append(0)
        self.frameData["ask_3_price"].append(0.)
        self.frameData["ask_3_volume"].append(0)
        self.frameData["ask_4_price"].append(0.)
        self.frameData["ask_4_volume"].append(0)
        self.frameData["ask_5_price"].append(0.)
        self.frameData["ask_5_volume"].append(0)

    def processLine(self,code,line):
        #get the value string from the equation
        fquote = line.find("\"")
        equote = line.rfind("\"")
        if fquote == -1 or equote == -1:
            self.ready = False
            self.insertEmptyRecord(code)
        else:
            found = line[fquote+1:equote]
            splits = found.split(",")
            if len(splits) > 10:
                self.frameData["code"].append(code)
                self.frameData["name"].append(splits[0])
                self.frameData["open"].append(float(splits[1]))
                self.frameData["last_close"].append(float(splits[2]))
                self.frameData["current"].append(float(splits[3]))
                self.frameData["highest"].append(float(splits[4]))
                self.frameData["lowest"].append(float(splits[5]))
                #bid
                #ask
                #self.frameData["current_volume"].append(int(splits[26]))
                self.frameData["total_volume"].append(int(splits[8]))
                self.frameData["total_value"].append(float(splits[9]))
                #self.frameData["holding_volume"].append(float(splits[29]))
                self.frameData["bid_1_price"].append(float(splits[11]))
                self.frameData["bid_1_volume"].append(int(splits[10]))
                self.frameData["bid_2_price"].append(float(splits[13]))
                self.frameData["bid_2_volume"].append(int(splits[12]))
                self.frameData["bid_3_price"].append(float(splits[15]))
                self.frameData["bid_3_volume"].append(int(splits[14]))
                self.frameData["bid_4_price"].append(float(splits[17]))
                self.frameData["bid_4_volume"].append(int(splits[16]))
                self.frameData["bid_5_price"].append(float(splits[19]))
                self.frameData["bid_5_volume"].append(int(splits[18]))
                self.frameData["ask_1_price"].append(float(splits[21]))
                self.frameData["ask_1_volume"].append(int(splits[20]))
                self.frameData["ask_2_price"].append(float(splits[23]))
                self.frameData["ask_2_volume"].append(int(splits[22]))
                self.frameData["ask_3_price"].append(float(splits[25]))
                self.frameData["ask_3_volume"].append(int(splits[24]))
                self.frameData["ask_4_price"].append(float(splits[27]))
                self.frameData["ask_4_volume"].append(int(splits[26]))
                self.frameData["ask_5_price"].append(float(splits[29]))
                self.frameData["ask_5_volume"].append(int(splits[28]))

            else:
                self.insertEmptyRecord(code)




    def __init__(self,codes,index):
        threading.Thread.__init__(self)
        self.codes = codes
        self.index = index
        self.frame = []
        self.ready = False
        self.frameData = {
            "code" : [],
            "name" : [],
            "last_close" : [],
            "open" : [],
            "current" : [],
            "highest" : [],
            "lowest" : [],
            "total_volume" : [],
            "total_value" : [],
            "ask_1_price" : [],
            "ask_1_volume" : [],
            "ask_2_price" : [],
            "ask_2_volume" : [],
            "ask_3_price" : [],
            "ask_3_volume" : [],
            "ask_4_price" : [],
            "ask_4_volume" : [],
            "ask_5_price" : [],
            "ask_5_volume" : [],
            "bid_1_price" : [],
            "bid_1_volume" : [],
            "bid_2_price" : [],
            "bid_2_volume" : [],
            "bid_3_price"  : [],
            "bid_3_volume" : [],
            "bid_4_price"  : [],
            "bid_4_volume" : [],
            "bid_5_price" : [],
            "bid_5_volume" : []

        }

    def run(self):
        codeString = ",".join(self.codes)
        self.ready = True
        ic = 0
        try:
            url = TickThread.baseUrl + codeString
            f = urllib.request.urlopen(url)
            #line = f.readline()

            # start = time.time()
            # while line != b"":
            #     #self.processLine(self.codes[ic],line.decode("GBK"))
            #     line = f.readline()
            #     ic += 1
            content = f.read().decode("GBK")
            lines = content.split("\n")
        except Exception as e:
            self.ready = False
            lines = [""] * len(self.codes)

        for line in lines:
            if ic == len(self.codes):
                break
            self.processLine(self.codes[ic],line)
            ic += 1
        self.frame = pd.DataFrame(self.frameData,self.index)
        # end = time.time()
        # print(end - start)
        # print("Thread done")


class CTPTickThread(threading.Thread):
    def __init__(self,host,startIndex):
        threading.Thread.__init__(self)
        self.context = zmq.Context()
        self.socket = self.context.socket(zmq.SUB)
        self.socket.connect("tcp://%s:5555" % (host))
        self.socket.setsockopt_string(zmq.SUBSCRIBE, "")
        self.ticks = {}
        self.startIndex = startIndex
        self.mutex = threading.Lock()
        print("Connected to CTP tick daemon")
        self.clearFrameData()

    def run(self):
        while(True):
            string = self.socket.recv_string()
            splits = string.split(";")
            self.mutex.acquire(True)
            self.ticks[splits[0]] = splits
            self.mutex.release()

    def clearFrameData(self):
        self.frameData = {
            "code" : [],
            "name" : [],
            "last_close" : [],
            "open" : [],
            "current" : [],
            "highest" : [],
            "lowest" : [],
            "total_volume" : [],
            "total_value" : [],
            "ask_1_price" : [],
            "ask_1_volume" : [],
            "ask_2_price" : [],
            "ask_2_volume" : [],
            "ask_3_price" : [],
            "ask_3_volume" : [],
            "ask_4_price" : [],
            "ask_4_volume" : [],
            "ask_5_price" : [],
            "ask_5_volume" : [],
            "bid_1_price" : [],
            "bid_1_volume" : [],
            "bid_2_price" : [],
            "bid_2_volume" : [],
            "bid_3_price"  : [],
            "bid_3_volume" : [],
            "bid_4_price"  : [],
            "bid_4_volume" : [],
            "bid_5_price" : [],
            "bid_5_volume" : []

        }

    def read(self):
        self.clearFrameData()
        self.mutex.acquire(True)
        self.frameData["code"] = self.ticks.keys()
        for k in self.ticks.keys():
            splits = self.ticks[k]
            self.frameData["name"].append(splits[1])
            self.frameData["open"].append(float(splits[2]))
            self.frameData["last_close"].append(float(splits[3]))
            self.frameData["current"].append(float(splits[4]))
            self.frameData["highest"].append(float(splits[5]))
            self.frameData["lowest"].append(float(splits[6]))
            self.frameData["total_volume"].append(int(splits[7]))
            self.frameData["total_value"].append(float(splits[8]))
            self.frameData["bid_1_price"].append(float(splits[9]))
            self.frameData["bid_1_volume"].append(int(splits[10]))
            self.frameData["bid_2_price"].append(float(splits[11]))
            self.frameData["bid_2_volume"].append(int(splits[12]))
            self.frameData["bid_3_price"].append(float(splits[13]))
            self.frameData["bid_3_volume"].append(int(splits[14]))
            self.frameData["bid_4_price"].append(float(splits[15]))
            self.frameData["bid_4_volume"].append(int(splits[16]))
            self.frameData["bid_5_price"].append(float(splits[17]))
            self.frameData["bid_5_volume"].append(int(splits[18]))
            self.frameData["ask_1_price"].append(float(splits[19]))
            self.frameData["ask_1_volume"].append(int(splits[20]))
            self.frameData["ask_2_price"].append(float(splits[21]))
            self.frameData["ask_2_volume"].append(int(splits[22]))
            self.frameData["ask_3_price"].append(float(splits[23]))
            self.frameData["ask_3_volume"].append(int(splits[24]))
            self.frameData["ask_4_price"].append(float(splits[25]))
            self.frameData["ask_4_volume"].append(int(splits[26]))
            self.frameData["ask_5_price"].append(float(splits[27]))
            self.frameData["ask_5_volume"].append(int(splits[28]))
        self.mutex.release()
        frame = pd.DataFrame(self.frameData,range(self.startIndex,self.startIndex+len(self.frameData["code"])))
        #print(frame)
        return frame

class SinaTick:
    def __init__(self,ctpHost,codeFiles,nParallel=300):
        self.codeFiles = codeFiles
        self.codes = []
        self.nParallel = nParallel
        self.ctpHost = ctpHost
        self.frame = None

    def readAllCodes(self):
        basepath = os.path.abspath(os.path.dirname(sys.argv[0]))

        for codeSec in self.codeFiles:
            pathname = codeSec #os.path.join(basepath,codeSec)
            f = open(pathname,"r")
            line = f.readline().strip()
            codes = line.split(",")
            self.codes.extend(codes)
            #print(codes)
        self.ctpThread = CTPTickThread(self.ctpHost,len(self.codes))
        self.ctpThread.start()

    def downloadTicks(self):
         start = 0
         step = self.nParallel
         iters = (len(self.codes) + self.nParallel)//self.nParallel
         frames = []
         delayed = 0
         while True:
             ready = True
             self.threads = []
             while start < len(self.codes):
                 end = start + step
                 if end > len(self.codes):
                     end = len(self.codes)
                 subCodes = self.codes[start:end]
                 subThread = TickThread(subCodes, range(start,end))
                 subThread.start()
                 self.threads.append(subThread)
                 start += step
             frames = []
             for thread in self.threads:
                 thread.join()
                 if(thread.ready):
                     frames.append(thread.frame)
                 ready = ready and thread.ready

             if ready or delayed == 5:
                 break
             time.sleep(1)
             delayed = delayed + 1

             print("Retry downloading tick\n")

         frames.append(self.ctpThread.read())
         result = pd.concat(frames)
         return (ready, result)
